// #include "include/blk.h"
#include "include/hvc.h"
#include "include/irq.h"
#include "include/shyper_service.h"
#include <linux/mm.h>
#include <linux/string.h>

// 10 is hard code
u64 share_mem_base_pa[10];

enum share_mem_type {
    MIGRATE_BITMAP = 0,
    VM_CONTEXT_SEND,
    VM_CONTEXT_RECEIVE,
    MIGRATE_SEND,
    MIGRATE_RECEIVE,
    LIVE_UPDATE_IMG
};

static int remap_pfn_open(struct inode *inode, struct file *file) {
    // struct mm_struct *mm = current->mm;
    // INFO("client: %s (%d)\n", current->comm, current->pid);
    // INFO("mmap  section: s: 0x%lx\n", mm->mmap_base);
    return 0;
}

int remap_pfn_mmap(struct file *file, struct vm_area_struct *vma) {
    int ret;
    unsigned long pfn_start;
    unsigned long size;

    unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
    // u64 base = base_addr;
    char *file_name = file->f_path.dentry->d_iname;
    u64 base_addr = 0;
    if (strcmp(file_name, "migrate_send") == 0) {
        base_addr = share_mem_base_pa[MIGRATE_SEND];
    } else if (strcmp(file_name, "migrate_receive") == 0) {
        base_addr = share_mem_base_pa[MIGRATE_RECEIVE];
    } else if (strcmp(file_name, "migrate_bitmap") == 0) {
        base_addr = share_mem_base_pa[MIGRATE_BITMAP];
    } else if (strcmp(file_name, "vm_ctx_send") == 0) {
        base_addr = share_mem_base_pa[VM_CONTEXT_SEND];
    } else if (strcmp(file_name, "vm_ctx_receive") == 0) {
        base_addr = share_mem_base_pa[VM_CONTEXT_RECEIVE];
    } else if (strcmp(file_name, "hyper_update") == 0) {
        base_addr = share_mem_base_pa[LIVE_UPDATE_IMG];
    } else {
        ERROR("map file %s failed\n", file_name);
    }

    pfn_start = (base_addr >> PAGE_SHIFT) + vma->vm_pgoff;
    size = vma->vm_end - vma->vm_start;

    // if (strcmp(file_name, "migrate_bitmap") == 0)
    INFO("[remap_pfn_mmap] phy: 0x%lx, offset: 0x%lx, size: 0x%lx\n",
         pfn_start << PAGE_SHIFT, offset, size);
    ret =
        remap_pfn_range(vma, vma->vm_start, pfn_start, size, vma->vm_page_prot);

    if (ret)
        ERROR("%s: remap_pfn_range failed at [0x%lx  0x%lx]\n", __func__,
              vma->vm_start, vma->vm_end);

    return ret;
};
static struct file_operations remap_pfn_fops = {
    .owner = THIS_MODULE,
    .open = remap_pfn_open,
    .mmap = remap_pfn_mmap,
};

struct miscdevice remap_pfn_misc_migrate_send = {
    .minor = MISC_DYNAMIC_MINOR,
    .name = "migrate_send",
    .fops = &remap_pfn_fops,
};
struct miscdevice remap_pfn_misc_migrate_receive = {
    .minor = MISC_DYNAMIC_MINOR,
    .name = "migrate_receive",
    .fops = &remap_pfn_fops,
};
struct miscdevice remap_pfn_misc_migrate_bitmap = {
    .minor = MISC_DYNAMIC_MINOR,
    .name = "migrate_bitmap",
    .fops = &remap_pfn_fops,
};
struct miscdevice remap_pfn_misc_vm_ctx_send = {
    .minor = MISC_DYNAMIC_MINOR,
    .name = "vm_ctx_send",
    .fops = &remap_pfn_fops,
};
struct miscdevice remap_pfn_misc_vm_ctx_receive = {
    .minor = MISC_DYNAMIC_MINOR,
    .name = "vm_ctx_receive",
    .fops = &remap_pfn_fops,
};
struct miscdevice remap_pfn_misc_hyper_update = {
    .minor = MISC_DYNAMIC_MINOR,
    .name = "hyper_update",
    .fops = &remap_pfn_fops,
};

void register_misc_dev(u64 len, u64 type, struct miscdevice *remap_pfn_misc) {
    int ret;
    u64 base_addr = hvc_call(type, len, 0, 0, 0, 0, 0,
                             HVC_MODE(HVC_IVC, HVC_IVC_SHARE_MEM));
    share_mem_base_pa[type] = base_addr;

    ret = misc_register(remap_pfn_misc); // 注册一个misc设备
    if (unlikely(ret)) {
        ERROR("failed to register misc device %s!\n", remap_pfn_misc->name);
        return;
    }
}

// get shyper dev irq number
// 注册中断
// 模拟设备请求
// 队列数据内存区间，vm与hypervisor均可访问
void register_misc(void) {
    INFO("start to register misc device for shared mem\n");

    register_misc_dev(0x100000000, MIGRATE_SEND, &remap_pfn_misc_migrate_send);
    register_misc_dev(0x100000000, MIGRATE_RECEIVE,
                      &remap_pfn_misc_migrate_receive);
    register_misc_dev(0x10000000, MIGRATE_BITMAP,
                      &remap_pfn_misc_migrate_bitmap);
    register_misc_dev(0x10000000, VM_CONTEXT_SEND, &remap_pfn_misc_vm_ctx_send);
    register_misc_dev(0x10000000, VM_CONTEXT_RECEIVE,
                      &remap_pfn_misc_vm_ctx_receive);
    // hard code for LIVE_UPDATE_IMG
    register_misc_dev(0x8000000, LIVE_UPDATE_IMG, &remap_pfn_misc_hyper_update);
}

void deregister_misc(void) {
    misc_deregister(&remap_pfn_misc_migrate_send);
    misc_deregister(&remap_pfn_misc_migrate_receive);
    misc_deregister(&remap_pfn_misc_migrate_bitmap);
    misc_deregister(&remap_pfn_misc_vm_ctx_send);
    misc_deregister(&remap_pfn_misc_vm_ctx_receive);
    misc_deregister(&remap_pfn_misc_hyper_update);
}
